1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.apache.tapestry5.internal.transform;
16
17 import java.util.Collections;
18 import java.util.Comparator;
19 import java.util.LinkedList;
20 import java.util.List;
21 import java.util.Set;
22
23 import org.apache.tapestry5.EventConstants;
24 import org.apache.tapestry5.annotations.PageActivationContext;
25 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
26 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
27 import org.apache.tapestry5.model.MutableComponentModel;
28 import org.apache.tapestry5.plastic.FieldHandle;
29 import org.apache.tapestry5.plastic.PlasticClass;
30 import org.apache.tapestry5.plastic.PlasticField;
31 import org.apache.tapestry5.runtime.Component;
32 import org.apache.tapestry5.runtime.ComponentEvent;
33 import org.apache.tapestry5.services.ComponentEventHandler;
34 import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
35 import org.apache.tapestry5.services.transform.TransformationSupport;
36
37
38
39
40
41
42 public class PageActivationContextWorker implements ComponentClassTransformWorker2
43 {
44 private static final Comparator<PlasticField> INDEX_COMPARATOR = new Comparator<PlasticField>()
45 {
46 public int compare(PlasticField field1, PlasticField field2) {
47 int index1 = field1.getAnnotation(PageActivationContext.class).index();
48 int index2 = field2.getAnnotation(PageActivationContext.class).index();
49
50 int compare = index1 < index2 ? -1 : (index1 > index2 ? 1 : 0);
51 if (compare == 0)
52 {
53 compare = field1.getName().compareTo(field2.getName());
54 }
55 return compare;
56 }
57 };
58
59 public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model)
60 {
61 List<PlasticField> fields = plasticClass.getFieldsWithAnnotation(PageActivationContext.class);
62
63 if (!fields.isEmpty())
64 {
65 transformFields(support, fields);
66 }
67 }
68
69 private void transformFields(TransformationSupport support, List<PlasticField> fields)
70 {
71 List<PlasticField> sortedFields = CollectionFactory.newList(fields);
72 Collections.sort(sortedFields, INDEX_COMPARATOR);
73 validateSortedFields(sortedFields);
74
75 PlasticField firstField = sortedFields.get(0);
76 PageActivationContext firstAnnotation = firstField.getAnnotation(PageActivationContext.class);
77
78
79 FieldHandle[] handles = new FieldHandle[sortedFields.size()];
80 String[] typeNames = new String[sortedFields.size()];
81
82 int i = 0;
83 for (PlasticField field : sortedFields) {
84 handles[i] = field.getHandle();
85 typeNames[i] = field.getTypeName();
86 ++i;
87 }
88
89 if (firstAnnotation.activate())
90 {
91 support.addEventHandler(EventConstants.ACTIVATE, 1,
92 "PageActivationContextWorker activate event handler", createActivationHandler(handles, typeNames));
93 }
94
95 if (firstAnnotation.passivate())
96 {
97 support.addEventHandler(EventConstants.PASSIVATE, 0,
98 "PageActivationContextWorker passivate event handler", createPassivateHandler(handles));
99 }
100
101
102 }
103
104 private void validateSortedFields(List<PlasticField> sortedFields) {
105 List<Integer> expectedIndexes = CollectionFactory.newList();
106 List<Integer> actualIndexes = CollectionFactory.newList();
107 Set<Boolean> activates = CollectionFactory.newSet();
108 Set<Boolean> passivates = CollectionFactory.newSet();
109
110 for (int i = 0; i < sortedFields.size(); ++i) {
111 PlasticField field = sortedFields.get(i);
112 PageActivationContext annotation = field.getAnnotation(PageActivationContext.class);
113 expectedIndexes.add(i);
114 actualIndexes.add(annotation.index());
115 activates.add(annotation.activate());
116 passivates.add(annotation.passivate());
117 }
118
119 List<String> errors = CollectionFactory.newList();
120 if (!expectedIndexes.equals(actualIndexes)) {
121 errors.add(String.format("Index values must start at 0 and increment by 1 (expected [%s], found [%s])",
122 InternalUtils.join(expectedIndexes), InternalUtils.join(actualIndexes)));
123 }
124 if (activates.size() > 1) {
125 errors.add("Illegal values for 'activate' (all fields must have the same value)");
126 }
127 if (passivates.size() > 1) {
128 errors.add("Illegal values for 'passivate' (all fields must have the same value)");
129 }
130 if (!errors.isEmpty()) {
131 throw new RuntimeException(String.format("Invalid values for @PageActivationContext: %s", InternalUtils.join(errors)));
132 }
133 }
134
135 private static ComponentEventHandler createActivationHandler(final FieldHandle[] handles, final String[] fieldTypes)
136 {
137 return new ComponentEventHandler()
138 {
139 public void handleEvent(Component instance, ComponentEvent event)
140 {
141 int count = Math.min(handles.length, event.getEventContext().getCount());
142 for (int i = 0; i < count; ++i)
143 {
144 String fieldType = fieldTypes[i];
145 FieldHandle handle = handles[i];
146 Object value = event.coerceContext(i, fieldType);
147 handle.set(instance, value);
148 }
149 }
150 };
151 }
152
153 private static ComponentEventHandler createPassivateHandler(final FieldHandle[] handles)
154 {
155 return new ComponentEventHandler()
156 {
157 public void handleEvent(Component instance, ComponentEvent event)
158 {
159 Object result;
160 if (handles.length == 1) {
161
162 result = handles[0].get(instance);
163 } else {
164 LinkedList<Object> list = CollectionFactory.newLinkedList();
165
166
167 for (int i = handles.length - 1; i > -1; i--) {
168 FieldHandle handle = handles[i];
169 Object value = handle.get(instance);
170
171
172 if (value != null || !list.isEmpty()) {
173 list.addFirst(value);
174 }
175 }
176 result = list.isEmpty() ? null : list;
177 }
178
179 event.storeResult(result);
180 }
181 };
182 }
183 }